package com.quectel.core.module.forum.service.impl.mongo;

import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.quectel.constant.core.forum.ForumConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.util.aspect.lock.annotation.Lock;
import com.quectel.core.config.TransactionManagerConfig;
import com.quectel.core.constants.MongoCollectionConstants;
import com.quectel.core.constants.RedisLockConstants;
import com.quectel.core.module.MongoAuthComponent;
import com.quectel.core.module.forum.dto.mongo.ForumPersonCountDto;
import com.quectel.core.module.forum.entity.mongo.ForumPersonCountModel;
import com.quectel.core.module.forum.service.mongo.ForumPersonCountService;
import com.quectel.core.module.mobileuser.dto.MobileUserDto;
import com.quectel.core.module.mobileuser.service.MobileUserService;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.Request;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mongo.MongodbUtils;
import com.quectel.util.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/5/8 15:52
 * @description 帖子
 */
@DubboService
@Slf4j
public class ForumPersonCountServiceImpl implements ForumPersonCountService {

    @Autowired
    private MongoAuthComponent mongoAuthComponent;

    @Autowired
    private MobileUserService mobileUserService;

    @Autowired
    private VillageService villageService;

    private Criteria sqlWhere(Map<String, Object> params) {
        Request request = Request.configParams(params);

        Criteria authByAllQuery = mongoAuthComponent.buildTenantConstraintsQuery(params
                , LambdaUtil.getFieldName(ForumPersonCountModel::getTenantId)
        );

        Criteria criteria = new Criteria();

        Long mobileUserId = request.getLong(LambdaUtil.getFieldName(ForumPersonCountModel::getMobileUserId));
        if (mobileUserId != null) {
            criteria.and(LambdaUtil.getFieldName(ForumPersonCountModel::getMobileUserId)).is(mobileUserId);
        }

        return new Criteria().andOperator(authByAllQuery, criteria);
    }

    @Override
    @Lock(
            lockExpresses = {
                    RedisLockConstants.FORUM_PERSON_COUNT_LOCK + "#{#dto.tenantId}" + ":" + "#{#dto.mobileUserId}"
            }
    )
    public void updateById(ForumPersonCountDto dto) {
        MongodbUtils.update(
                new Query(
                        Criteria.where(SystemConstants.MONGO_ENTITY_ID_FLAG).is(dto.getId())
                ),
                new Update()
                        .set(LambdaUtil.getFieldName(ForumPersonCountModel::getPostCount), dto.getPostCount())
                        .set(LambdaUtil.getFieldName(ForumPersonCountModel::getCommentCount), dto.getCommentCount())
                        .set(LambdaUtil.getFieldName(ForumPersonCountModel::getLikeCount), dto.getLikeCount())
                        .set(LambdaUtil.getFieldName(ForumPersonCountModel::getShareCount), dto.getShareCount())
                ,
                MongoCollectionConstants.FORUM_PERSON_COUNT

        );
    }

    @Override
    @Lock(
            lockExpresses = {
                    RedisLockConstants.FORUM_PERSON_COUNT_LOCK + "#{#tenantId}"  + ":" + "#{#mobileUserId}"
            }
    )
    @Transactional(transactionManager = TransactionManagerConfig.MONGO_TRANSACTION_MANAGER, rollbackFor = RuntimeException.class)
    public void updateCommentCount(Long tenantId, Long mobileUserId, Byte handleType, Integer offset) {
        ForumPersonCountService forumPersonCountService = SpringUtils.getBean(ForumPersonCountService.class);
        ForumPersonCountDto forumPersonCountDto = selectByTenantAndUser(tenantId, mobileUserId);
        if (forumPersonCountDto == null) {
            forumPersonCountDto = new ForumPersonCountDto();
            forumPersonCountDto.setTenantId(tenantId);
            forumPersonCountDto.setMobileUserId(mobileUserId);
            Long save = forumPersonCountService.save(forumPersonCountDto);
            forumPersonCountDto.setId(save);
        }

        ForumConstants.ForumHandleType byType = ForumConstants.ForumHandleType.getByType(handleType);
        if (byType == null) {
            return;
        }

        Integer count = 0;
        try {
            Field field = ReflectionUtils.findField(ForumPersonCountDto.class, byType.getFieldName() + "Count");
            if (field != null) {
                field.setAccessible(true);
                count = (Integer) field.get(forumPersonCountDto);
                count += offset;
                ReflectionUtils.setField(field, forumPersonCountDto, count <= 0 ? 0 : count);

                forumPersonCountService.updateById(forumPersonCountDto);
            }
        } catch (IllegalAccessException e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public ForumPersonCountDto selectByTenantAndUser(Long tenantId, Long mobileUserId) {

        ForumPersonCountModel one = MongodbUtils.findOneData(ForumPersonCountModel.class, new Query(
                        Criteria.where(LambdaUtil.getFieldName(ForumPersonCountModel::getTenantId)).is(tenantId)
                                .and(LambdaUtil.getFieldName(ForumPersonCountModel::getMobileUserId)).is(mobileUserId))
                , MongoCollectionConstants.FORUM_PERSON_COUNT);
        return CopyUtils.copyObj(one, ForumPersonCountDto.class);

    }


    @Override
    public ForumPersonCountDto selectById(Long id) {
        ForumPersonCountModel one = MongodbUtils.findOne(id, MongoCollectionConstants.FORUM_PERSON_COUNT, ForumPersonCountModel.class);
        return CopyUtils.copyObj(one, ForumPersonCountDto.class);
    }

    @Override
    public List<ForumPersonCountDto> queryList(Map<String, Object> params) {
        Request request = Request.configParams(params);
        return
                MongodbUtils.page(
                        new Query(sqlWhere(params)),
                        request.getPageNo() - 1,
                        request.getPageSize(),
                        Sort.by(Sort.Order.desc(LambdaUtil.getFieldName(ForumPersonCountModel::getPostCount)) ,Sort.Order.desc(SystemConstants.ENTITY_ID_FLAG)),
                        ForumPersonCountModel.class,
                        MongoCollectionConstants.FORUM_PERSON_COUNT
                ).stream().map(model -> {
                    ForumPersonCountDto dto = CopyUtils.copyObj(model, ForumPersonCountDto.class);

                    MobileUserDto mobileUserDto = mobileUserService.selectCacheById(dto.getMobileUserId());
                    if (mobileUserDto != null) {
                        dto.setMobile(DesensitizedUtil.mobilePhone(mobileUserDto.getMobile()));
                        dto.setName(DesensitizedUtil.chineseName(mobileUserDto.getName()));
                        dto.setHeadImg(mobileUserDto.getHeadImg());
                    }

                    return dto;
                }).collect(Collectors.toList());
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return (int) MongodbUtils.count(new Query(sqlWhere(params)), MongoCollectionConstants.FORUM_PERSON_COUNT);
    }

    @Override
    public Long save(ForumPersonCountDto dto) {
        ForumPersonCountModel entity = CopyUtils.copyObj(dto, ForumPersonCountModel.class);
        entity.setId(Snowflake.nextId());
        MongodbUtils.insert(entity, MongoCollectionConstants.FORUM_PERSON_COUNT);
        return entity.getId();
    }


    @Override
    public void deleteById(Long id) {
        MongodbUtils.delete(id, MongoCollectionConstants.FORUM_PERSON_COUNT);
    }

    @Override
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            MongodbUtils.delete(id, MongoCollectionConstants.FORUM_PERSON_COUNT);
        }
    }

}
